# -*-coding:utf-8-*-

# import tornado.web
# import tornado.wsgi
import logging
import tornado
from tornado.options import define, options
import pyrestful.rest
import pymongo
import motor
import settings
from tornado.gen import coroutine, Return
from bson.objectid import ObjectId
import functools


define('port', default=settings.MAIN_SERVICE_DEFAULT_PORT,
       help='Run service on a specific port', type=int)
define('wsgi', default=False, help='Use WSGI or Proxy mode', type=bool)
define('prod', default=True, help='Run in product mode or not', type=bool)
options.parse_command_line()

from daos.apps import AppsDao, App
from daos.roles import RolesDao
from daos.users import UsersDao
from daos.devices import DevicesDao
from daos.areas import AreasDao
from daos.rooms import RoomsDao
from daos.orders import OrdersDao
from daos.products import ProductsDao
from daos.transfers import TransfersDao
from daos.jobs import JobsDao

from handlers.entries import EntriesHandler
from handlers.users import UsersHandler
from handlers.devices import DevicesHandler
from handlers.devices_services import DevicesServicesHandler
from handlers.devices_states import DevicesStatesHandler
from handlers.devices_statistics import DevicesStatisticsHandler

from handlers.weixin.mp import WXMPHandler
from handlers.weixin.pay import WXPayHandler
from handlers.allinpay.pay import AllinpayHandler
from handlers.alipay.pay import AlipayHandler

from handlers.platform.apps import AppsHandler
from handlers.platform.roles import RolesHandler
from handlers.platform.users import PlatformUsersHandler
from handlers.platform.devices import PlatformDevicesHandler
from handlers.platform.areas import AreasHandler
from handlers.platform.rooms import RoomsHandler
from handlers.platform.products import ProductsHandler
from handlers.platform.orders import PlatformOrdersHandler
from handlers.platform.transfers import TransfersHandler
from handlers.platform.jobs import JobsHandler

from handlers.spec.devices import SpecDevicesHandler

# Note the order of handlers in the following array
handlers = [
    WXMPHandler,
    WXPayHandler,
    AllinpayHandler,
    AlipayHandler,

    AppsHandler,
    RolesHandler,

    EntriesHandler,
    UsersHandler,
    # 注意 statistics handler 要声明在 device handler 前面才能保证 statistics handler 正常工作
    DevicesStatisticsHandler,
    DevicesHandler,

    DevicesServicesHandler,
    DevicesStatesHandler,

    AreasHandler,
    RoomsHandler,

    PlatformDevicesHandler,
    PlatformUsersHandler,
    PlatformOrdersHandler,

    ProductsHandler,
    TransfersHandler,
    JobsHandler,

    SpecDevicesHandler,
]


def get_daos(db, **kwargs):
    daos = dict()
    for k, v in kwargs.iteritems():
        daos.update({k: v(db)})
    return daos

ROOT_USER_ID = settings.root_user_id
ROOT_APP_KEY = 'CA7E0BE302DF22F9CF4315BDCF66B62D'
ROOT_APPS = {
    ROOT_APP_KEY: {
        'name': 'bora',
        'desc': 'root APP of BORA service',
        'app_id': '013A50065E93147B09245E657712A227',
        'secret': '720BFFF2C9C9627A4C36C119AB2361AA',
        'weixin': {
            # billy's wx mp no. `microembed`
            'mp': {
                'app_id': 'wx1ed17c5f860f88f6',
                'secret': '957c86a1e7389e2f868b6d3b12314999',
                'verify_token': 'iot2018',
            }
        },
        'alidayu': {
            'appkey': '23749569',
            'secret': '47fdda3390d660126278322e36a39cc4',
            'sms': {
                'sign_name': '智能管家',
                'register_code': 'SMS_77775036',
                'reset_password_code': 'SMS_77765047',
                'change_phone_code': 'SMS_77630040',
            }
        },
        'alipay': {
            'appid': '',
            'rsa2': {
                'app_priv': '',
                'app_pub': '',
                'srv_pub': '',
            },
        },
        'alipay_sandbox': {
            'appid': '',
            'rsa2': {
                'app_pri': '',
                'app_pub': '',
                'srv_pub': '',
            },
        },
    },
    '403DB206089258FBB529B861AB768D59': {
        'name': '公众平台测试号',
        'desc': '公众平台号测试',
        'app_id': '12E4F3314D9E24718332FA45B6E704F1',
        'secret': '07BC866EC1149EC6BD54497C2143BDEA',
        'guest_enable': True,
        'guest_id': '5b7a5302f3e0985613626f58',
        'use_alipay_sandbox': True,
        'weixin': {
            # billy's test no
            'mp': {
                'app_id': 'wx83b0dfc9866ac48c',
                'secret': 'd8cf6396e8e50c25592529a75feadb16',
                'verify_token': 'iot2017',
            },
        },
        'alipay': {
            'appid': '2018081861041794',
            'mch_id': '2088112315985801',
            'rsa2': {
                'app_priv': 'MIIEowIBAAKCAQEArqDTHkiISP0AFQdPew6rlTIlM0h4Fwxu209DYxkyag6zB+wBwlHHeaWK07fv2+mlKSi3bxN3qdQImQ+W27Ba0zYRrffZTQUKdo48IiEUZKtfyXVCJAN7oBDnles+FhjVIXyLZ+z14duqU2PA5bVwhTODoyeE0tyGY62mIfDWemYb19zK6mlgyxI9A8saeOEfKaTRtj3OT7EJurFAlcZlY593Ci8WnAStBrP7CJSCRvB7xLYYprgT/QVtK+8+Vm5F9FMfAhg4wNoaePDzTIdOojRW8Qx8Qs+HDZWFvFzYxWZcertW1ocIiRkZ6sxs0vA/OyfiHZE/eJ2WzoSlraEvqQIDAQABAoIBAD86+Ha0qLRU95ylov/Z1gMVvyaMjP87f0BluO6/BuQkImsx54km92VyrYvvxCgKt8Tpe1H66I9TuTFC1csCVkC4CTrGzaX3t0wqQFfTRoEVFH/rt2E26aKRvGkqXra9kx6m7AtbX8TCNzAupIAIbI+ukXGYM53uP7MEA22yuNZkXUi4ZNlh/8wHPcq3HXM/DP5oCrIYinOBrpVYqp/cClBas334G1GzX1Le6sk7cJiauGGkvUE3nab71xcmVnApJtwyJJvk2pmxkyzcIUuaoH0JAP7hUCByLJugRiwrCrygWph26NRyByDpHJk4ff2V3ZasWmc6NwFNwiBm4+9icwECgYEA3s1RGAPgZ+wferI4VTj3pQtbkVi+TW5AqsQCzMaj4dbiNPJiEqtxIxdwxRGIvYTz1rHLY7fQuuZxbbabZto+HisB/9NK4wuObzZVKJc3dJ+47BFt73UjcB+VhRjkNmDAZ41xwo/+fSdkMxZ+i6ksjKQtJGNWejA01gZd7IFLXpECgYEAyKXwouS8LlYJdYIhmi4QLpCVv4382r6SEmEJuC2Q6q3Y/C3mKMAm9P4PpdBQgwPYK67bRStvzqZSxcvgEaud4Vj7J3Iwn1zrCsBL7+iDRDBsStWVSHP6Lv05I1mEVyOxSuYQlTXTAg+8kQSJWggK6FR2CWY0qX+Bl980gb3Ge5kCgYAWSpqLeY/RNfmsT/p85Fc6pxlBQIzBuH811qilDlbFOLenLn0LeyW1qhm5TdjNhWjUGTPNRU3X9Uhx/qwrrTg70ne/vccnUjes/tWkWwTMYVKiI9hI9gJWrIJML8Jdgm6drbQtEDUZFoDa76w3kvSHGcH+ewXi8cHHjBmHmSQOUQKBgQDE340tR6IdFO5TDkxKK8hU6CkGuxrOxw4sWmpe/Nakbc/qIF8kvOV8nYxc9fkJlEwXEIq1Y9lgunGdAl3o+KsA4X4NRk3PECzPb78StuGVlq2q/8ZqQOHKGUxnEv53Qd5Dz1mWDinsa+RppjnezOVm8PigYFhrt2BA1BGA++Q0gQKBgEWEzri96kEbqNOrB2zx4+Kx1fLbKgiYozRhRA+d7UtZPn4Kt3hHHgMK4Bc4gISRqFMX46UgBlQYJazwBvVGF1edYxZljNbHRWgFByzOaYnKPqtBxNNNhyVMGGepP/YR+WW5NyVWgoQBHMVm5AeH5wg82lGd1/Xsj/bc3viMvtjV',
                'app_pub': 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArqDTHkiISP0AFQdPew6rlTIlM0h4Fwxu209DYxkyag6zB+wBwlHHeaWK07fv2+mlKSi3bxN3qdQImQ+W27Ba0zYRrffZTQUKdo48IiEUZKtfyXVCJAN7oBDnles+FhjVIXyLZ+z14duqU2PA5bVwhTODoyeE0tyGY62mIfDWemYb19zK6mlgyxI9A8saeOEfKaTRtj3OT7EJurFAlcZlY593Ci8WnAStBrP7CJSCRvB7xLYYprgT/QVtK+8+Vm5F9FMfAhg4wNoaePDzTIdOojRW8Qx8Qs+HDZWFvFzYxWZcertW1ocIiRkZ6sxs0vA/OyfiHZE/eJ2WzoSlraEvqQIDAQAB',
                'srv_pub': 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0axTSkSIR7Bl/OmPQ8/kGky9+wznWxVIPuCmYb5TG4NVKxF3WQfdZWVkpa1fSRKbIeywd2LojaCQLVItnPYkqAGMcgDC13Yc4CKekcfeNV9eOtXQRxtvtTGss8ZrFmmJy5XtPjGbIJjt9D/bfauE/+dfQeqEUm6s6ymOv/xKM8PJztYwwLbjdTTOWEoEONFqgrdXVCUT0dYCH9Qbon7j9zXAiBQ5PUwTUpeLS5ZmmFX1MXaX3y6fOjn8CRZfkOfVEFNfKq0n4xSKIrpjb03Xv8knyG2pJE90pAsFET1PmkOv7j4BFFsZaMwEtk1U19UX/DKu5KNjTyhu7d55P2ohaQIDAQAB',
            },
        },
        'alipay_sandbox': {
            'appid': '2016091700535282',
            'mch_id': '2088102176093759',
            'rsa2': {
                'app_pri': 'MIIEogIBAAKCAQEAuTPdvG4PxqfqFyEBT8MeQqWXZYBhBj2Zbs0NGRgI9uk4NFzaAoAdziDbwKUxIZaDDl2KRqO8pE6i+R8UyUxb/w6A6D1ARthk8UT2aSQazVm4wHNqtJvtsjVjY3CpSuN8BKlf6L8Vyd1Wu/siVHGnMtwMOZwyRaSDfOMrtT58mIbd4gouxn7CYjepdLFQu1lGoKPDWwRq7+TD9AT35fMpBFGO8t2xnkdSdx771O93uqm9Q18p22kpDKC7zPfuDIUiCswvVSc1Uc8oARAWietHHXF5+VtATuX9NB42wSKrhDwSWem6MUhf68Nr/65nhUVoyVkD7SKos0HiZl23H35BawIDAQABAoIBAF/ZhgLFe4i20qJRxJoBQ6H+jZJMlOpj6wq7OPIpzEntfdcrzvDIWaSawOC9HeZiPUWsB6pzh2gKArKn8VwVFu+0E+cd/CwuRl/P7y+PLgflTYbctPbwVF6M3vlSD2vgvAi1mBue+anV0dPML4JAp+XcmL8gJayBbkOuVqqgwl81XAFxSAvdTe2EgdDenYtFziI9g1iwDzROCKqgqzFG97YxJHGm3WegdbYS8rKtRPYzZKcoSmrt/U5O7oaptSzABeH/4wXPTXDj+RqY11PONvpL4b5Xy0MVzX5rZwTVeljen9tlMaN5cAmF073FODhMZgBr4Gd320gfU6ZfKVD0alECgYEA4txXftQetiOTHR6FWsjoLt4PBUtj5XiyeZfmvYE1z12fHZMCnltMLt5/zTfl2vP619SjwjaR7HwFsrVb6rbmL4QSibpVEsZeDIg+HauizwtJbJOMmREOo44MyY/lqEAvAzj2+4G4EiRFyO09mX8lsk0SbWgQloy5TcWiOZyW2v8CgYEA0P23zvV1orUurLC9ZnACQMYCo4mGhzbCurlGmBcLFUqMn+B46wd2J7KzjgiAMCuAZX8O1uL0Xlxf02Luz8QEsxSykxmtvvmgVx++YQz54Jn977QjzvcwAAbSXOcd8/TmPmgk/TSHiYTYqrK6yVz2Sgzb1+b2EEdkKFJlqUGmNZUCgYBa34B84WNb+mwXof4xG4FGJNVHfaeKaAq2Ak7/Yh637fyq0BSgclnV/HKdNeLxDgJRKnBef5V8cUGnEFa9cn5KUlFKskUZvDQ4OOsI35Pb8915jLEpL1f51BDzPJz2BJ/QXqUwogml2rnJfp7KOdBT1+Olx6W9aKlhqeUNxtf26QKBgDMGj1cvZP5J4FB3gna9SD+KWOCW1kqzGw496DeAAMu8/OKYCs3Pb5C3t9Eo0Ctyo5GkWPosRV+4jAjvccE2abNTjVoO/fXPus8qx++oHGYzEuXwhIGmpoiLIdde8lg65fA8uzM7HRB9Z+0dYC+Dy/o+c3qeQFuvIowZugp+JdeVAoGARcjIuQspvTPOUQTk2OyZa2ZwYVRSOyAGIXd9nh2TmJJ/NgttuwqpDpvCYbpSBjD+rv8JZbLN6gRO/ibmreniubvwt2GG8FvtM/YHBz5BwZPIsthdTHJ7zuKoyZbItwaW1yuaCN813vkXY8gN442Gpzdp0Yv2eitDnmOP0QgSpgQ=',
                'app_pub': 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuTPdvG4PxqfqFyEBT8MeQqWXZYBhBj2Zbs0NGRgI9uk4NFzaAoAdziDbwKUxIZaDDl2KRqO8pE6i+R8UyUxb/w6A6D1ARthk8UT2aSQazVm4wHNqtJvtsjVjY3CpSuN8BKlf6L8Vyd1Wu/siVHGnMtwMOZwyRaSDfOMrtT58mIbd4gouxn7CYjepdLFQu1lGoKPDWwRq7+TD9AT35fMpBFGO8t2xnkdSdx771O93uqm9Q18p22kpDKC7zPfuDIUiCswvVSc1Uc8oARAWietHHXF5+VtATuX9NB42wSKrhDwSWem6MUhf68Nr/65nhUVoyVkD7SKos0HiZl23H35BawIDAQAB',
                'srv_pub': 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3gWO8tFBQeUMzQED9LUOQcRzRMhaivhqD2ksB+SczIz1gFNFkJ/rStv3O17mx5sWj1c9nnyBFcKWiRET52528nQFZkHXDJnaEurncH6rE2oO2DoDw/LaF/ouEnW5D8MI7mo0k6pTiA4pJP3qkpACN73UDcAr6b+io2snbzqxGrwDaW9haNMfwRxO61BnDyXc2dI2y4ku0HWFpxAYjhM3/noqxZOs5FgbJWYcc0QhyxVhCsBQYLha2yCJV9yfvTod4lKimTE4OR3613JlYm0l5YB9bdFkhalenIzkvjJYQFR+hKH4lk7pq3MaQFqnozFyx/f78nEZ4U0H5ysreNSrLQIDAQAB',
            },
        },

        'email': {
            # TODO: SMTP 配置
        },

        'ios': {
            # TODO: APNS 配置
        },
    },
}


def add_root_user(daos_async):
    @coroutine
    def add_root_user_async(apps_dao, users_dao):
        yield add_root_apps(apps_dao)
        
        app = yield apps_dao.get_app(ROOT_APP_KEY)
        data = {
            '_id': ObjectId(ROOT_USER_ID),
            'username': '13411383600',
            'password': '36c7e0214fad84b571a439ad575d9d7b',  # billyiot
            'roles': ['5a587776d823ef4e582422de'],
        }
        yield users_dao.add_user(app, data)

        # TMP: debug purpose
        yield tmp_import_apps_from_settings(apps_dao)

    @coroutine
    def add_root_apps(apps_dao):
        apps = ROOT_APPS
        for key, app in apps.iteritems():
            exists = yield apps_dao.get_app(key)
            if not exists:
                app['appkey'] = key
                app['user_id'] = ROOT_USER_ID
                app['developer_id'] = ROOT_USER_ID
                yield apps_dao.insert_one(app)

    @coroutine
    def tmp_import_apps_from_settings(apps_dao):
        # TMP/NOTE: 每次部署都从 settings 加载最新的 app list
        apps = settings.APPS
        apps_dao.delete_many({'appkey': {'$in': apps.keys()}})
        for key, app in apps.iteritems():
            app['appkey'] = key
            app['user_id'] = ROOT_USER_ID
            app['developer_id'] = '5ad8a81d97c2095144d9b283'
            yield apps_dao.insert_one(app)

    func = functools.partial(
        add_root_user_async, daos_async['apps'], daos_async['users'])
    tornado.ioloop.IOLoop.instance().run_sync(func)


def main(wsgi):
    logger = logging.getLogger()
    logger.info('API server start at port %d' % options.port)

    # db = pymongo.MongoClient(host='119.23.25.240').bora
    db_name = 'bora_v2' if options.prod else 'bora_v2_test'
    logger.info('db_name: %s' % db_name)
    db = pymongo.MongoClient().get_database(db_name)
    db_async = motor.MotorClient().get_database(db_name)
    daos = get_daos(db, areas=AreasDao, rooms=RoomsDao)
    daos_async = get_daos(db_async,
                          apps=AppsDao,
                          roles=RolesDao,
                          users=UsersDao, devices=DevicesDao,
                          orders=OrdersDao, products=ProductsDao,
                          transfers=TransfersDao,
                          jobs=JobsDao)
    kwargs = dict(db=db, db_async=db_async, daos=daos, daos_async=daos_async)
    if wsgi:
        from flup.server.fcgi_fork import WSGIServer
        # application = tornado.wsgi.WSGIApplication(routes)
        application = pyrestful.rest.WSGIRestService(handlers, **kwargs)
        # WSGIServer(application=application, bindAddress=('', options.port), xheaders=True).run()
        WSGIServer(application=application,
                   bindAddress=('', options.port)).run()
    else:
        # application = tornado.web.Application(routes)
        if not options.prod:
            # 注意：每次启动测试都会清空数据库
            pymongo.MongoClient().drop_database(db_name)
            kwargs.update(debug=True, autoreload=True)
        application = pyrestful.rest.RestService(handlers, **kwargs)
        # To get remote_ip, it should set xheaders=True when initializing HTTPServer
        application.listen(options.port, xheaders=True)
        add_root_user(daos_async)
        tornado.ioloop.IOLoop.instance().start()


if __name__ == '__main__':
    main(options.wsgi)
